﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;

using System.Linq;

using ProjectBase.Core;

using $prjsn$.Common;
using $prjsn$.Common.Validation;

namespace $safeprojectname$
{
    /// <summary>
    ///     Project based Mother Facade.
    ///     Every stuff which is project dependent and common for all entities
    ///     should be placed here
    /// </summary>
    /// <typeparam name = "TEntity">Entity</typeparam>
    /// <typeparam name = "TID"></typeparam>
    /// <typeparam name = "TDao"></typeparam>
    /// <typeparam name = "TFilter"></typeparam>
    public abstract class ReadFacade<TEntity, TID, TFilter, TDao> : Facade, IReadFacade<TEntity, TID, TFilter>
        where TEntity : class, IPersistentObjectWithTypedId<TID>
        where TDao : class, IReadDao<TEntity, TID, TFilter>
        where TFilter : class, IFilter<TID>
    {
        // members
        private static readonly IList<string> FilterExcludedProperties = new[] { Constants.Common.Excel.ExportAllRows
            , "OrderBy", "ProjectionList", "ProfileId" };

        #region Factory Method

        /// <summary>
        ///     Returns new transient entity 'T'.
        ///     If overriden, some properties could be preset to business defaults.
        ///     (Business rules therefore should be met)
        /// </summary>
        /// <returns>new entity 'T' transient</returns>
        public abstract TEntity CreateNew();

        #endregion Factory Method

        #region IReadFacade

        /// <summary>
        ///     Basic read operation for getting known entity
        /// </summary>
        /// <param name = "id">Entity unique int identifier</param>
        /// <returns>Entity instance or null</returns>
        public virtual TEntity GetById(TID id)
        {
            var entity = Dao.GetById(id);
            return entity;
        }

        /// <summary>
        ///     Fundamental (and powerful) read operation for filter-List.
        ///     Overriden implementations can use more specific filter
        /// </summary>
        /// <param name = "filter">basic filter parameters cluster, could be extended for Entity purposes and casted</param>
        /// <returns>Paged list of entities matching filter criteria</returns>
        public virtual IEnumerable<TEntity> Find(TFilter filter)
        {
            var isFilterValid = filter.Is()
                && FilterValidator.Validate(filter, this);

            if (isFilterValid)
            {
                var result = Dao.Find(filter);
                if (result.Is())
                {
                    return result;
                }
            }

            this.PublishError(Str.Messages.IncorrectFilteres);

            return new List<TEntity>();
        }

        public virtual TFilter BindFilter(TFilter filter
            , IValueContainer valueContainer
            , string prefix = null
            , string[] includeProperties = null
            , string[] excludeProperties = null)
        {
            if (filter.IsNull())
            {
                return filter;
            }

            var exclude = ExcludedFilterProperties;

            if (excludeProperties.IsNotEmpty())
            {
                exclude = exclude.Union(excludeProperties).ToArray();
            }
            filter = Binder.Bind(filter, valueContainer, prefix, includeProperties, exclude);

            // convert filter.OrderRows into OrderBy dictionary
            filter.ApplyOrderBy();

            return filter;
        }

        protected virtual IList<string> ExcludedFilterProperties
        {
            get { return FilterExcludedProperties; }
        }

        public abstract TFilter CreateNewFilter();

        #endregion IReadFacade

        #region DAO

        /// <summary>
        ///     Dao (Data-access-object), storage dependent CRUD operations.
        /// </summary>
        public virtual TDao Dao { get; set; }

        #endregion DAO

        #region Validator

        /// <summary>
        /// Returns the (JS) string representation of the UI evaluable validation rules.
        /// (Example: validator.rules["LastName"] = { required: true, minlength: 1,maxlength: 50};)
        /// </summary>
        /// <param name = "validationType">The filter rule. (e.g. "filter" for read; "Add", "Update" for write)</param>
        /// <returns>(JS) validation rules</returns>
        public virtual string ValidationRulesToString(string validationType)
        {
            var rulesForFilter = validationType.IsEqual(Str.Actions.Find)
                || validationType.IsEqual(Str.Actions.Search);
            if (rulesForFilter)
            {
                return FilterValidator.ValidationRulesToString(validationType);
            }
            return string.Empty;
        }

        public IFilterValidator<TFilter, TID> FilterValidator { protected get; set; }

        #endregion Validator
    }
}